import {
  useMemo,
  useCallback,
  useState,
  useContext,
  forwardRef,
  useImperativeHandle,
  ForwardedRef,
  useEffect,
  useRef,
} from 'react';
import { InfiniteScroll, Popup, Empty } from 'antd-mobile';
import { useRequest, useUpdateEffect, useInViewport } from 'ahooks';
import { getSearchData, ISearchData } from '../../../designer/service';
import { IConfigItemEngineProps } from '../../web/index';
import useTemplate from '../../common/useTemplate';
import {
  ISearchEngineData,
  getDefaultParams,
  IConfigItem,
  ISearchResultContentRef,
} from '../../common/useConfigs';
import ContentBody from './contentBody';
import ContentHead from './contentHead';
import { InbizIcon } from '@inbiz/utils';
import Category from './category';
import SystemGroup, { ISystemGroupChildren } from '../../common/SystemGroup';
import EventContext from '../../common/EventContext';
import { getMessage, TextWidget } from '@inbiz/react';
import filterImg from '../../assets/filter.svg'
export type { IConfigItem };
export type ICategorySelect = (key: string[]) => void;
function SearchResultContent(
  {
    option,
    engineProps,
    searchEngineData,
  }: {
    option: Exclude<IConfigItemEngineProps['indexIibraryConfig'], undefined>[number];
    engineProps: IConfigItemEngineProps;
    searchEngineData: ISearchEngineData;
  },
  ref: ForwardedRef<ISearchResultContentRef>,
) {
  // InbizConfig.PUBLIC_PATH + '/template_mobile/section.jsx'
  const { configEventsApi, emit, configEvents } = useContext(EventContext);
  const config = useMemo(() => {
    const index =
      option.IndexName === '_document_' ? (searchEngineData.documentType == 'folder' ? 1 : 0) : 0;
    if (option.configs?.[index]) {
      return {
        ...option.configs?.[index]!,
        IndexName: option.configs?.[index].IndexName!,
      };
    }
    return {
      ...option.configs?.[0]!,
      IndexName: option.configs?.[0].IndexName!,
    };
  }, [option, searchEngineData]);
  // 结果详情模板
  const [view] = useTemplate(config.columnType === 'custom' ? config.template?.content : '');
  // 自定义切面模板
  const [SectionView] = useTemplate(config.sectionType === 'custom' ? (config.sectionTemplate?.content || InbizConfig.PUBLIC_PATH + '/template_mobile/section.jsx') : '');
  
  // 请求数据参数
  const [params, $params] = useState(() =>
    getDefaultParams(config, {
      platform: 'wap',
      PageIndex: 0,
      pageNumber: engineProps.pageNumber,
      ...searchEngineData,
    }),
  );
  useUpdateEffect(() => {
    // 为0 时重新加载数据
    if (params.PageIndex === 0) {
      $selected([]);
      $dataSoure([]);
      emit?.('onSelectClear', config.IndexName);
    }
  }, [params.PageIndex, config.IndexName]);
  // 后台返回的切面数据， 直接给到切面模板
  const resSectionList = useRef<ISearchData["SectionList"]>([]);
  const [dataSoure, $dataSoure] = useState<ISearchData['RawList']>([]);
  const { data, runAsync, error, loading } = useRequest(
    (params) => {
      return configEventsApi({
        request: getSearchData,
        params,
        keys: ['onSearchParams', 'onSearch', 'onSearchData'],
      });
    },
    {
      onSuccess: (data) => {
        resSectionList.current = data.SectionList;
        $dataSoure((list) => [...list, ...(data.RawList || [])]);
        $sectionList((list) => {
          if (list?.length) {
            return list;
          } else {
            return data.SectionList;
          }
        });
      },
      debounceWait: 100,
      manual: true,
    },
  );
  // 切面数据
  const [sectionList, $sectionList] = useState<ISearchData['SectionList']>([]);
  const [sectionVisible, $sectionVisible] = useState(false);
  useUpdateEffect(() => {
    // groupNum, KeyWord 变更时，重新加载切面
    $sectionList([]);
  }, [params.groupNum, params.KeyWord]);

  useUpdateEffect(() => {
    $sectionList([]);
    $categorySelected([]);
    
    $params(
      getDefaultParams(config, {
        PageIndex: 0,
        pageNumber: engineProps.pageNumber,
        IsSynonymSearch: searchEngineData.IsSynonymSearch,
        ...searchEngineData,
      }),
    );
  }, [searchEngineData]);

  // 选中的切面
  const [categorySelected, $categorySelected] = useState<string[]>([]);
  const handleCategoryChange: ICategorySelect = useCallback((keys: string[]) => {
    $categorySelected(keys);
    $sectionVisible(false);
  }, []);
  useUpdateEffect(() => {
    $params((params) => ({
      ...params,
      PageIndex: 0,
      SearchWhere: convertSection(categorySelected, [(config as unknown as {resultsSearchCriteria:string}).resultsSearchCriteria, searchEngineData.SearchWhere!]),
    }));
  }, [categorySelected]);

  // 唯一key
  const uniqueKey = useMemo(() => {
    return config.columnField?.[0]?.IndexFieldName || '_id';
  }, [(config as unknown as {uniqueField:string}).uniqueField]);

  // 选中的数据项
  const [selected, $selected] = useState<ISearchData['RawList']>([]);
  const handleSelectedChange = useCallback(
    (dataParam: (typeof selected)[number], checked: boolean) => {
      $selected((list) => {
        if (checked) {
          const newList = [...list, dataParam];
          emit?.('onSelect', {
            data: dataParam,
            selected: checked,
            selectedAll: newList,
            IndexName: config.IndexName,
          });
          return newList;
        } else {
          const newList = [...list];
          const index = newList.findIndex(
            (item) => item.RawData[uniqueKey] === dataParam.RawData[uniqueKey],
          );
          newList.splice(index, 1);
          emit?.('onSelect', {
            data: dataParam,
            selected: checked,
            selectedAll: newList,
            IndexName: config.IndexName,
          });
          return newList;
        }
      });
    },
    [config.IndexName],
  );

  const $content = useRef<HTMLDivElement>(null);
  // 修复在tabs中，InfiniteScroll 不工作的问题
  const [inViewport] = useInViewport($content);

  // 加载数据
  const loadMore = useCallback(() => {
    return runAsync({
      ...params,
      PageIndex: params.PageIndex + 1,
    })
      .then(() => {
        $params((params) => ({ ...params, PageIndex: params.PageIndex + 1 }));
      })
      .catch((e) => {
        // 错误时 不从重新请求需要PageIndex 大于0
        $params((data) => ({ ...data, PageIndex: 1 }));
      });
  }, [params]);

  // 排序字段选中
  const [sort, $sort] = useState({ IndexFieldName: params.Sort!, order: params.Order });
  const handleSortChange = useCallback(({ IndexFieldName, order }: typeof sort) => {
    if (order) {
      $sort({ IndexFieldName, order });
    } else {
      $sort({ IndexFieldName, order: undefined });
    }
    $params((params) => ({
      ...params,
      PageIndex: 0,
      Sort: order ? IndexFieldName : '',
      Order: order ? order : 'desc',
    }));
  }, []);
  // 系统分类变更
  const handleSystemGroupChange = useCallback(
    (key?:string) => {
      // 排序恢复成默认排序
      const { Sort, Order } = getDefaultParams(config, {} as typeof searchEngineData);
      $sort({ IndexFieldName: Sort!, order: Order });
      // 清空选中的切面
      $categorySelected([]);
      // 更新参数
      $params((params) => ({ ...params, Sort, Order, groupNum: key, PageIndex: 0 }));
    },
    [config],
  );

  const SystemGroupChildren: ISystemGroupChildren = useCallback(
    (list, onClick, selectedGroupName) => {
      return (
        <ul className="systemGroupBox">
          {list.map((item) => {
            return (
              <li
                key={item.groupNum}
                onClick={() => onClick(item.groupNum)}
                className={item.groupNum === selectedGroupName ? 'selected' : ''}
              >
                {item.groupName}
              </li>
            );
          })}
        </ul>
      );
    },
    [],
  );
  // 对外暴露的方法
  useImperativeHandle(
    ref,
    () => ({
      getSelected: () => selected,
      getData: () => dataSoure,
    }),
    [selected, dataSoure],
  );
  const isShowContentHead = useMemo(() => {
    return config.sortField?.some((item) => item.enable) || config.section;
  }, [config]);

  const isShowContent = useMemo(() => {
    if (config.columnType != 'custom') {
      return true;
    } else {
      return !!(view?.ListView || view?.ThumbnailView);
    }
  }, [config.columnType, view]);
  const ContentMainView = useMemo(() => {
    const viewDom = (
      <>
        <span className='contentTotal'>
          <TextWidget>SearchResultEngine.findAnAppointmentForYou</TextWidget>
          <span className="number"> {data?.Total || 0} </span>
          <TextWidget>SearchResultEngine.relatedResults</TextWidget>
        </span>
        {isShowContentHead && (
          <div className="contentHeader">
            {config.sectionType === 'custom' ? SectionView?.default && <SectionView.default 
              sectionList={resSectionList.current} 
              config={config} 
              entry={engineProps} 
              configEvents={configEvents}
              emit={emit}
              searchEngineData={searchEngineData}
              getConvertSection={(category: string[]) => convertSection(category, [(config as unknown as {resultsSearchCriteria:string}).resultsSearchCriteria, searchEngineData.SearchWhere!])}
              onSearch={$params}
              /> :
               <ContentHead
                  config={config}
                  sort={sort}
                  onSortChange={handleSortChange}
                  sortField={config.sortField}
                >
                  {config.section && (
                    <div className="sectionBtnBox" onClick={() => $sectionVisible(true)}>
                      <InbizIcon style={{ width: 20, height: 20 }} type={filterImg} />
                    </div>
                  )}
              </ContentHead>
            }
          </div> 
        )}
        {isShowContent && (
          <div className="contentMain">
            <ContentBody
              view={view}
              config={config}
              dataSoure={dataSoure}
              showStyle={'list'}
              selected={selected}
              onSelect={handleSelectedChange}
              uniqueKey={uniqueKey}
            />
            {!loading && !dataSoure?.length && params.PageIndex != 0 ? (
              <Empty
                image={<InbizIcon type="icon-ic-zanwushuju" />}
                description={getMessage('SearchResultEngine.noData')}
              />
            ) : (
              <InfiniteScroll
                loadMore={loadMore}
                hasMore={
                  error || !inViewport
                    ? false
                    : !data || params.PageIndex === 0 || data.RawList?.length == params.PageSize
                }
              />
            )}
          </div>
        )}
      </>
    );
    if (config.columnType == 'list') {
      return viewDom;
    } else {
      if (view) {
        if (view.MainView) {
          const MainView = view.MainView;
          return (
            <MainView
              data={data}
              dataSoure={dataSoure}
              showStyle="list"
              handleShowSection={$sectionVisible}
              {...{
                sort,
                handleSortChange,
                config,
                loading,
                selected,
                handleSelectedChange,
                uniqueKey,
              }}
              InfiniteScroll={
                <InfiniteScroll
                  loadMore={loadMore}
                  hasMore={
                    error || !inViewport
                      ? false
                      : !data || params.PageIndex === 0 || data.RawList?.length == params.PageSize
                  }
                />
              }
            />
          );
        } else {
          return viewDom;
        }
      } else {
        return null;
      }
    }
  }, [
    isShowContentHead,
    isShowContent,
    sort,
    handleSortChange,
    config,
    dataSoure,
    selected,
    handleSelectedChange,
    uniqueKey,
    loading,
    error,
    inViewport,
    params,
    loadMore,
    view,
    searchEngineData,
    SectionView
  ]);
  return (
    <div className="searchResultContentWap" ref={$content}>
      <SystemGroup
        config={config}
        showSystem={config.showSystem && option.IndexName !== '_document_'}
        onChange={handleSystemGroupChange}
      >
        {SystemGroupChildren}
      </SystemGroup>
      {ContentMainView}

      <Popup
        visible={sectionVisible}
        position="right"
        bodyStyle={{ width: '285px' }}
        onMaskClick={() => $sectionVisible(false)}
        destroyOnClose
      >
        <Category
          list={sectionList}
          selected={categorySelected}
          onSelected={handleCategoryChange}
        />
      </Popup>
    </div>
  );
}

export default forwardRef(SearchResultContent);

// 将已选择切面数据转换成字符串
function convertSection (section: string[], other: string[]) {
  const category: { [key in string]: string[] } = section.reduce((pre, next) => {
    const index = next.indexOf(':'),
      key = next.slice(0, index),
      value = next.slice(index + 1);
      //@ts-ignore
    if (pre[key]) {
       //@ts-ignore
      pre[key].push(value);
    } else {
       //@ts-ignore
      pre[key] = [value];
    }
    return pre;
  }, {});

  const categoryData = Object.entries(category).map(([key, value]) => {
    if (value[0][0] === '[') {
      return `(${value.map((item) => `(${key}:${item})`).join(' OR ')})`;
    } else {
      return `${key}:(${value.map((item) => item.slice(1, -1)).join(' OR ')})`;
    }
  });
  return [...other, ...categoryData].filter((item) => !!item).join(' AND ');
}